package com.mfs.proxy.core.server.registry;

import com.mfs.common.constant.Constant;
import com.mfs.common.utills.Assert;
import com.mfs.common.utills.StringUtil;
import com.mfs.common.utills.TaskUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 超时 代理客户端注册中心默认实现
 *
 * @author mfs
 * @date 2023/7/1 14:54
 **/
public class DefaultTimeoutProxyClientRegistry extends AbstractTimeoutProxyClientRegistry {
    private static Logger logger = LoggerFactory.getLogger(DefaultTimeoutProxyClientRegistry.class);
    /**
     * 每个客户端的上次活跃时间
     * */
    private Map<String, Long> address2LastTimeAlive = new ConcurrentHashMap<>();
    /**
     * 超时时间 单位毫秒，默认2分钟
     * */
    private long timeout = 2 * 60 * 1000;

    /**
     * 定时任务执行器
     * */
    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(Constant.ONE);

    public DefaultTimeoutProxyClientRegistry() {
        super();
        init();
    }
    public DefaultTimeoutProxyClientRegistry(long timeout) {
        super();
        this.timeout = timeout;
        init();
    }

    /**
     * 启动超时监视器
     * */
    private void init() {
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            for (Map.Entry<String, Long> item : address2LastTimeAlive.entrySet()) {
                long now = System.currentTimeMillis();
                if (now - item.getValue() >= timeout) {
                    logger.debug("Proxy client({}) is poorly active and ready to be released.", item.getKey());
                    unregister(item.getKey());
                }
            }
        }, timeout, timeout, TimeUnit.MILLISECONDS);
    }

    public boolean unregister(String proxyAddress) {
        Assert.notBlank(proxyAddress, "proxyAddress can't be blank");
        String[] split = proxyAddress.split(Constant.COLON);
        String proxyIp = split[0];
        Integer proxyPort = split.length > Constant.ONE && StringUtil.isInt(split[1]) ? Integer.valueOf(split[1]) : null;
        Assert.notNull(proxyPort, "can't find the port");
        return super.unregister(proxyIp, proxyPort);
    }

    @Override
    public boolean timeoutRegister(String proxyIp, Integer proxyPort) {
        address2LastTimeAlive.putIfAbsent(getAddress(proxyIp, proxyPort), System.currentTimeMillis());
        return true;
    }

    @Override
    public boolean timeoutUnregister(String proxyIp, Integer proxyPort) {
        address2LastTimeAlive.remove(getAddress(proxyIp, proxyPort));
        return true;
    }

    @Override
    public void hello(String proxyIp, Integer proxyPort) {
        address2LastTimeAlive.computeIfPresent(getAddress(proxyIp, proxyPort), (key, value) -> System.currentTimeMillis());
    }
}
